﻿using System.IO;
using UnityEngine;

public class FogUtility
{
    public static int MapSize = 10;
    public static int TextureSize = 10;
    public static int ScaleSize = 1;
    public static Texture2D FogDataMask = null;
    public static byte[] FogUnlockData;
    public static byte[] FogSelectData;
    public static Color ColorIsLocked =  new Color(0,0,0,1);
    public static Color ColorIsUnlocked =  new Color(1, 0, 0, 1);
    public static Color ColorSelected = new Color(0, 1, 0, 1);
    public static Color ColorDiscovering = new Color(0, 0.5f, 0, 1);

    public static bool DoFixPrecision = true;
    public static int UpscaleTextureSize = 1024;

    /*
    public GameObject FogObj;
    private void Start()
    {
        InitFog(FogObj, GenerateFakeData(), 10);
    }*/

    public static void InitFog(GameObject fogObj , byte[] unlockedData,int mapSize, int scaleSize=1) {
        InitFogAttribute( mapSize,  scaleSize,  unlockedData);
        InitFogMask();
        ApplyFogMask(fogObj);
    }

    public static void UpdateSelectedFog(GameObject fogObj, byte[] selectedData) {
        InitFogMask();
        ApplyFogMask(fogObj);
    }

    public static void InitFogAttribute(int mapSize, int scaleSize, byte[] unlockedData)
    {
        FogUtility.MapSize = mapSize;
        FogUtility.ScaleSize = scaleSize;
        FogUtility.TextureSize = mapSize * scaleSize;
        FogUtility.FogUnlockData = unlockedData;

        if (FogUtility.DoFixPrecision) //InitPrecisionFix
            FogUtility.UpscaleTextureSize = FogUtility.UpscaleTextureSize * scaleSize;
    }

    public static void UpdateFogMask(int x, int y, int fogState)
    {
        if (FogUtility.DoFixPrecision)
            CheckDataMaskFixedP();
        else
            CheckDataMask();

        FogUtility.FogDataMask.SetPixel(x, y, GetFogMaskColor(fogState));
    }

    private static void InitFogMask()
    {
        if (FogUtility.DoFixPrecision)
            CheckDataMaskFixedP();
        else
            CheckDataMask();

        for (int i = 0; i < FogUtility.TextureSize; i++)
        {
            for (int j = 0; j < FogUtility.TextureSize; j++)
            {
                if (FogUtility.HasFog(i, j))
                {
                    FogUtility.FogDataMask.SetPixel(i, j, ColorIsLocked);
                }
                else
                {
                    FogUtility.FogDataMask.SetPixel(i, j, ColorIsUnlocked);
                }
            }
        }
    }

    public static void ApplyFogMask(GameObject fogObj)
    {
        if (FogUtility.FogDataMask != null)
        {
            FogUtility.FogDataMask.Apply();
            fogObj.GetComponent<MeshRenderer>().material.SetTexture("_FogMask", FogUtility.FogDataMask);
        }
        fogObj.GetComponent<MeshRenderer>().material.SetFloat("_ArraySize", FogUtility.TextureSize);

        if (FogUtility.DoFixPrecision)
            ApplyPrecisionFix(fogObj);
    }

    private static bool HasFog(int x, int y) {
        if (x >= FogUtility.TextureSize || x < 0 || y < 0 || y >= FogUtility.TextureSize)
        {
            return false;
        }
        int index = GetTileIndex(x, y);
        return FogUnlockData[index] == 0;
    }

    private static int GetTileIndex(int x, int y) {
        return y * MapSize + x;
    }

    private static void WriteFile(Texture2D texture) {
        texture.Apply();
        var bytes = ImageConversion.EncodeToPNG(texture);
        //var file = Path.Combine(Application.dataPath, string.Format("Grid_{0}_{1}.png", row, col));
        var file = Path.Combine(Application.dataPath, "Tex_FogMask.png");
        File.WriteAllBytes(file, bytes);
    }

    private static Color GetFogMaskColor(int fogState) {
        FogState state = (FogState)fogState;
        switch (state) {
            case FogState.Locked:
                return ColorIsLocked;
            case FogState.Unlocked:
                return ColorIsUnlocked;
            case FogState.Selected:
                return ColorSelected;
            case FogState.Discovering:
                return ColorDiscovering;
            default:
                return ColorIsLocked;
        }
    }

    private static void CheckDataMask() {
        if (FogDataMask == null)
        {
            // TODO: RGBA32过大，要减小
            FogDataMask = new Texture2D(TextureSize, TextureSize, TextureFormat.RGBA32, false, true)
            {
                filterMode = FilterMode.Point,
                name = "FogDataMask"
            };
        }
    }

    private static void CheckDataMaskFixedP()
    {
        if (FogUtility.FogDataMask == null)
        {
            FogUtility.FogDataMask = new Texture2D(FogUtility.UpscaleTextureSize, FogUtility.UpscaleTextureSize, TextureFormat.RGBA32, false, true);
            FogUtility.FogDataMask.filterMode = FilterMode.Point;
        }
    }

    private static void ApplyPrecisionFix(GameObject fogObj)
    {
        Material fogMat = fogObj.GetComponent<MeshRenderer>().material;
        fogMat.SetFloat("_ArraySize", FogUtility.UpscaleTextureSize);
        fogMat.SetInt("_InitialTexSize", FogUtility.TextureSize);
        fogMat.SetInt("_DoExpandTex", FogUtility.DoFixPrecision ? 1 : 0);
    }

    public static byte[] GenerateFakeData() {
        byte[] unlockedData = new byte[100];
        unlockedData[54] = 1;
        unlockedData[55] = 1;
        unlockedData[65] = 1;
        unlockedData[66] = 1;
        return unlockedData;
    }
}

public enum FogState {
    Locked = 0,
    Unlocked = 1,
    Selected = 2,
    Discovering = 3,
}
